//
//  IvanNetStream.h
//  
//
//  Created by Ivan on 11-10-5.
//  Copyright 2011年 __MyCompanyName__. All rights reserved.
//

#import <Foundation/Foundation.h>

#import <CFNetwork/CFNetwork.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import <netinet/in.h>
#import <arpa/inet.h>

#import "Utility.h"
#define IVAN_DEBUG

#define BUFFER_SIZE             10 * 1024    // the max BUFFER_SIZE is 64KB. Greater than 64KB can be very dangerous!!!
#define MAX_RECONNECT_TIMES     5
#define PACKET_HEAD_SIZE        sizeof(NSInteger)

#define MODE_SYNC               0
#define MODE_ASYNC              1

/* IvanNetStreamDelegate defined the interface of controller which use IvanNetStream to communicate
   with server. Those controller must inherit IvanNetStreamDelegate
 */

typedef enum {
    IvanNSEventReady                                = 1,        // net connect ready
    IvanNSEventErrorOperationCouldNotBeCompleted    = 22,
    IvanNSEventErrorConnectionResetByPeer           = 54,
    IvanNSEventErrorServerRefuse                    = 61,

} IvanNetStreamEvent;

@protocol IvanNetStreamDelegate
- (void)getData:(NSData *)receivedData flag:(int)flag;
- (void)readInStream:(NSInputStream *)inStream;
- (NSData *)preProcessData:(UInt8 *)rawData length:(NSInteger)length outLength:(NSInteger *)outLength;
- (void)callBackHandle:(IvanNetStreamEvent)eventCode info:(id)info;
@end

#define IVAN_NET_STREAM [IvanNetStream sharedIvanNetStream]
@interface IvanNetStream:NSObject <NSStreamDelegate>
{    
    NSInputStream   *_inStream;               // receive data from the stream
    NSOutputStream  *_outStream;              // send data stream
    NSMutableData   *_dataBuffer;             // receive buffer
    
    UInt8           _writeBuffer[BUFFER_SIZE];// send buffer
    NSInteger       _wbHead;                  // send buffer head
    NSInteger       _wbTail;                  // send buffer tail
    
    BOOL            _hasEstablished;          //
    id              _currentDelegate;
    int             _numCondition;
    BOOL            _isFirstFourBytes;
    uint            remainingToRead;
    Boolean         _canWrite;
    
    NSString        *_serverURL;              // remote server url or ip address
    CFIndex         _port;                    // remote server port
    
    // property
    NSInteger       _packetHeaderSize;        //  
    
    //~property
    
    
    NSThread        *_asyncListener;          // the listener (thread) to recieve data and send data
    Boolean         _run;
    NSRunLoop       *_runLoopOfAsyncListener; // the runloop in the listener (thread)
}
@property (assign, nonatomic) NSInteger     packetHeaderSize;



+ (IvanNetStream *)sharedIvanNetStream;
- (id)initSingleton;

- (Boolean)connectWithServer:(NSString *)server port:(CFIndex)port delegate:(NSObject <IvanNetStreamDelegate> *)delegate;
- (void)asyncListener;
- (void)disconnect;

// for write
- (void)preWriteBytes:(UInt8 *)bytes length:(NSInteger)length;
- (void)preWriteBoolean:(Boolean)boolValue;
- (void)preWriteInt8:(UInt8)int8Value;
- (void)preWriteInt32:(NSInteger)intValue;
- (void)preWriteInt64:(UInt64)int64Value;
- (void)preWriteString:(NSString *)stringValue;
- (void)preWriteArray:(NSArray *)arrayValue;

- (void)writeToBuffer:(UInt8 *)buffer maxLength:(NSInteger)length;
- (void)writeFlush:(NSOutputStream *)outStream forMode:(NSInteger)forMode;
- (NSOutputStream *)getWriteFlushOutStream;

// deprecated
- (void)writeFlush;

@end

@interface IvanNetStream (private)

- (Boolean)startConnect;
- (Boolean)openStreams;
- (void)closeStreams;

- (Boolean)reconnect;
- (BOOL)isServerAvailable;
- (void)stream:(NSStream*)aStream handleEvent:(NSStreamEvent)eventCode;
- (void)dumpToBuffer:(NSOutputStream *)outStream;
@end

